package com.example.rbacmanage.filter;


import com.alibaba.druid.support.json.JSONUtils;
import com.example.rbacmanage.common.Constant;
import com.example.rbacmanage.config.MyUserDetailsService;
import com.example.rbacmanage.exception.MyException;
import com.example.rbacmanage.util.JwtTokenUtil;
import com.example.rbacmanage.util.SpringUtils;
import com.example.rbacmanage.vo.MyUserDetails;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class DefinedFilter extends OncePerRequestFilter {
    private final RequestMappingHandlerMapping handlerMapping = SpringUtils.getBean("requestMappingHandlerMapping");
    private final HandlerExceptionResolver handlerExceptionResolver = SpringUtils.getBean("handlerExceptionResolver");
    private final RedisTemplate<String, Object> redisTemplate = SpringUtils.getBean("redisTemplate");
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String uri = request.getRequestURI();

        //不拦截映射图片
        if (uri.contains("profile")  ) {
            filterChain.doFilter(request, response);
            return;
        }

        //判断请求接口是否存在
        try{
            Object handler = handlerMapping.getHandler(request);
            if (handler == null && !uri.equals("/")){
                handlerExceptionResolver.resolveException(request,response,null,new MyException(HttpStatus.NOT_FOUND.getReasonPhrase(), HttpStatus.NOT_FOUND.value()));
                return;
            }
        }catch (Exception e){

        }

        System.out.println("uri:"+uri);
        if (!uri.contains("app_user")&& !uri.contains("appUser")){
            if ( uri.contains("captcha") || uri.contains("/app/") || uri.contains("login") || uri.contains("register") ||uri.contains("profile")  ) {
                filterChain.doFilter(request, response);
                return;
            }
        }

        String token = request.getHeader("Authorization");
        System.out.println("token:"+token);
        if (token == null || token.equals("") ) {
            usernameExpired(response);
            return;
        }
        String username = JwtTokenUtil.getUsernameFromToken(token);
        if (!StringUtils.isEmpty(username) && SecurityContextHolder.getContext().getAuthentication() == null && JwtTokenUtil.validateToken(token,username)) {
            boolean tokenValid = redisTemplate.hasKey(Constant.systemLoginUserToken+username);
            if (tokenValid) {
                String redisToken = (String) redisTemplate.opsForValue().get(Constant.systemLoginUserToken+username);
                if (token.equals(redisToken)) {
                    System.out.println("token is valid");
                    MyUserDetailsService myUserDetailsService =  SpringUtils.getBean("myUserDetailsService");
                    MyUserDetails userDetails = myUserDetailsService.loadUserByUsername(username);
                    System.out.println("token is valid");
                    UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails,null,userDetails.getAuthorities());
                    authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);
                }else{
                    usernameInvalid(response);
                    return;
                }
            }else{
                usernameExpired(response);
                return;
            }
        }else{
            usernameInvalid(response);
            return;
        }
        //放行
        filterChain.doFilter(request, response);
    }

    /**
     * 账户无效
     */
    public void usernameInvalid(HttpServletResponse response){
        Map<String,Object> map = new HashMap<>();
        map.put("code",403);
        map.put("msg","token is invalid");
        map.put("data",null);
        try {
            response.getWriter().write(JSONUtils.toJSONString(map));
            response.flushBuffer();
        }catch (Exception e){

        }
    }
    /**
     * 账户过期
     */
    public void usernameExpired(HttpServletResponse response){
        Map<String,Object> map = new HashMap<>();
        map.put("code",401);
        map.put("msg","token is expired");
        map.put("data",null);
        try {
            response.getWriter().write(JSONUtils.toJSONString(map));
            response.flushBuffer();
        }catch (Exception e){

        }
    }

    @Override
    public void destroy() {

    }
}
